package com.zhu.rpc;

import com.google.gson.Gson;
import com.zhu.rpc.client.RemoteConsumer;
import com.zhu.rpc.client.RpcMsgCallBack;
import com.zhu.rpc.msgBean.RpcRequestBean;
import com.zhu.rpc.server.RpcProtocolProviderBean;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

//json格式：{name:\"userServerImpl,getUserInfo,java.lang.String,int\",param:[\"hhe11\",12]}
public class RpcProtocol {
    public static Map<String, RpcMsgCallBack> msgMap = new ConcurrentHashMap<>();

    public static RpcProtocolProviderBean decode(RpcProtocolProviderBean protocolBean){
//        RpcProtocolProviderBean protocolBean = gson.fromJson(msgStr, RpcProtocolProviderBean.class);
        Method method = RpcMethod.providerMethodMap.get(protocolBean.getName());

        Class[] c = method.getParameterTypes();
        int paramCount = method.getParameterCount();
        if (paramCount !=0){
            Object[] oArr = new Object[protocolBean.getParam().length];
            for (int i = 0; i < protocolBean.getParam().length; i++) {
                Object o;
                if (i < paramCount){
                    o = getParamObj(c[i],protocolBean.getParam()[i]);
                }else {
                    o = getParamObj(c[paramCount-1],protocolBean.getParam()[i]);
                }
                oArr[i] = o;
            }
            protocolBean.setoParam(oArr);
        }
        return protocolBean;
    }

    public static String getConsumerMethodRpcName(Method m){
        Class cla = m.getDeclaringClass();
        Class[] paramTypes = m.getParameterTypes();
        RemoteConsumer remoteConsumer = (RemoteConsumer) cla.getAnnotation(RemoteConsumer.class);
        String className = remoteConsumer.name();
        StringBuilder name = new StringBuilder(className).append(",").append(m.getName());
        for (Class t:paramTypes){
            if (RpcProtocol.isNolmalType(t)){
                name.append(",").append(t.getName());
            }else {
                name.append(",").append(t.getSimpleName());
            }
        }
        return name.toString();
    }
    public static RpcMsgCallBack encode(Method m,String mName,Object[] paramValue,StringBuilder sendMsg){
        changeObjToJsonstr(m,paramValue);
        RpcRequestBean rpcRequest = new RpcRequestBean(getConsumerMethodRpcName(m),paramValue,UUID.randomUUID().toString());
        RpcMsgCallBack rpcMsgCallBack = new RpcMsgCallBack(rpcRequest,mName);
        msgMap.put(rpcRequest.getMsgId(),rpcMsgCallBack);
        sendMsg.append(JsonUtil.toJson(rpcRequest));
        return rpcMsgCallBack;
    }

    private static void changeObjToJsonstr(Method m,Object[] paramValue){
        //把json对象转化为字符串
        Class[] types = m.getParameterTypes();
        for (int i = 0; i < types.length; i++) {
            if (!isNolmalType(types[i])){
                paramValue[i] = JsonUtil.toJson(paramValue[i]);
            }
        }
    }


    public static Object getParamObj(Class<?> classType,String value){
        String clsName = classType.getName();
        Object o = null;
        switch (clsName){
            case "java.lang.String":
                o = value;
                break;
            case "int":
            case "java.lang.Integer":
                o = Double.valueOf(value).intValue();
                break;
            case "long":
            case "java.lang.Long":
                o = new Long(value);
                break;
            case "short":
            case "java.lang.Short":
                o = new Short(value);
                break;
            case "boolean":
            case "java.lang.Boolean":
                o = Boolean.valueOf(value);
                break;
            case "char":
            case "java.lang.Character":
                o = value.toCharArray()[0];
                break;
            case "byte":
            case "java.lang.Byte":
                o = new Byte(value);
                break;
            case "double":
            case "java.lang.Double":
                o = new Double(value);
                break;
            case "float":
            case "java.lang.Float":
                o = new Float(value);
                break;
            case "java.lang.Object":
                o = value;
                break;
            default:
                o = JsonUtil.getObj(value,classType);
                //TODO json数据
                break;
        }
        return o;
    }

    //是否是基本类型
    public static boolean isNolmalType(Class<?> classType){
        String clsName = classType.getName();
        Object o = null;
        switch (clsName){
            case "java.lang.String":
            case "int":
            case "java.lang.Integer":
            case "long":
            case "java.lang.Long":
            case "short":
            case "java.lang.Short":
            case "boolean":
            case "java.lang.Boolean":
            case "char":
            case "java.lang.Character":
            case "byte":
            case "java.lang.Byte":
            case "double":
            case "java.lang.Double":
            case "float":
            case "java.lang.Float":
                return true;
            default:
                //TODO 不是基本类型
                return false;
        }
    }
}
